#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
# @version: v1.0
# @author : cd
# @Email : 19688513@qq.com
# @Project : new-horizons-engine
# @File : TradeDateManager.py
# @Software: PyCharm
# @time: 2025/5/30 11:47
# @description : 
"""

import urllib3
import logging

import sqlite3
from typing import List, Tuple

from datetime import datetime, date

from AKShareDataFetcher import AKShareDataFetcher
from DatabaseManager import DatabaseManager

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# 禁用不安全的请求警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


class TradeDateManager:
    def __init__(self, db_manager: DatabaseManager):
        """
        初始化 TradeDateManager 类

        Args:
            db_manager (DatabaseManager): DatabaseManager实例
        """
        self.db_manager = db_manager

    def read_trade_dates(self):
        """从 SQLite 数据库读取交易日期数据，并返回日期列表"""
        try:
            with self.db_manager.get_connection() as conn:
                cursor = conn.cursor()
                cursor.execute("SELECT trade_date FROM trade_dates ORDER BY trade_date")
                rows = cursor.fetchall()
                return [row[0] for row in rows]
        except sqlite3.Error as e:
            logging.error(f"读取交易日期数据失败: {e}")
            return []

    def is_tool_trading_day(self, date):
        """判断给定日期是否为工具交易日"""
        if date is None:
            raise ValueError("日期不能为空")

        try:
            with self.db_manager.get_connection() as conn:
                cursor = conn.cursor()
                date_str = date.strftime('%Y-%m-%d')
                cursor.execute("SELECT 1 FROM trade_dates WHERE trade_date = ?", (date_str,))
                return cursor.fetchone() is not None
        except sqlite3.Error as e:
            logging.error(f"判断交易日失败: {e}")
            return False

    def get_start_end_date(self, trade_date: str, y_day: int):
        """根据给定的交易日期和天数，计算起始日期和结束日期"""
        try:
            # 统一将 trade_date 转为字符串
            if isinstance(trade_date, date):
                trade_date_str = trade_date.strftime('%Y-%m-%d')
            elif isinstance(trade_date, str):
                trade_date_str = trade_date
            else:
                raise ValueError("交易日期必须是 datetime.date 或字符串格式")

            with self.db_manager.get_connection() as conn:
                cursor = conn.cursor()

                # 获取交易日期列表（直接返回 datetime 对象）
                cursor.execute("SELECT trade_date FROM trade_dates ORDER BY trade_date")
                trade_dates = [row[0] for row in cursor.fetchall()]  # row[0] 是 datetime 对象

                if trade_dates and trade_date_str in [dt.strftime('%Y-%m-%d') for dt in trade_dates]:
                    index = next(i for i, dt in enumerate(trade_dates) if dt.strftime('%Y-%m-%d') == trade_date_str)
                    start_index = max(0, index - y_day)
                    end_index = index
                    start_date = trade_dates[start_index].strftime('%Y-%m-%d')
                    end_date = trade_dates[end_index].strftime('%Y-%m-%d')
                    return start_date, end_date
                else:
                    # 自动查找最近的有效日期
                    target_dt = datetime.strptime(trade_date_str, '%Y-%m-%d')
                    closest_dt = min(
                        trade_dates,
                        key=lambda x: abs(x - target_dt)  # 直接使用 datetime 对象计算差值
                    )
                    closest_date_str = closest_dt.strftime('%Y-%m-%d')
                    logging.warning(f"目标日期 {trade_date_str} 不存在，使用最近日期 {closest_date_str} 替代")
                    return self.get_start_end_date(closest_date_str, y_day)
        except Exception as e:
            logging.error(f"获取起始结束日期失败: {e}")
            raise ValueError("数据库操作失败")

    def get_offset_trade_dates(self, trade_date, offset_days: int):
        """获取给定交易日期的偏移交易日期"""
        try:
            # 统一将 trade_date 转为字符串
            if isinstance(trade_date, date):
                trade_date_str = trade_date.strftime('%Y-%m-%d')
            elif isinstance(trade_date, str):
                trade_date_str = trade_date
            else:
                raise ValueError("交易日期必须是 datetime.date 或字符串格式")

            with self.db_manager.get_connection() as conn:
                cursor = conn.cursor()

                # 获取交易日期列表（直接返回 datetime 对象）
                cursor.execute("SELECT trade_date FROM trade_dates ORDER BY trade_date")
                tool_days = [row[0] for row in cursor.fetchall()]  # row[0] 是 datetime 对象

                if trade_date_str in [dt.strftime('%Y-%m-%d') for dt in tool_days]:
                    # 找到匹配的日期索引
                    index = next(i for i, dt in enumerate(tool_days) if dt.strftime('%Y-%m-%d') == trade_date_str)
                    previous_index = max(0, index - offset_days)
                    next_index = min(len(tool_days) - 1, index + offset_days)

                    previous_trade_date = tool_days[previous_index].strftime('%Y-%m-%d')
                    next_trade_date = tool_days[next_index].strftime('%Y-%m-%d') if next_index != index else None

                    return previous_trade_date, next_trade_date
                else:
                    # 自动查找最近的有效日期
                    target_dt = datetime.strptime(trade_date_str, '%Y-%m-%d')
                    closest_dt = min(
                        tool_days,
                        key=lambda x: abs(x - target_dt)  # 直接使用 datetime 对象计算差值
                    )
                    closest_date_str = closest_dt.strftime('%Y-%m-%d')
                    logging.warning(f"目标日期 {trade_date_str} 不存在，使用最近日期 {closest_date_str} 替代")
                    return self.get_offset_trade_dates(closest_date_str, offset_days)
        except Exception as e:
            logging.error(f"获取偏移交易日期失败: {e}")
            raise ValueError("数据库操作失败")

    def delete_trade_date(self, trade_date: str):
        """删除指定的交易日期"""
        try:
            with self.db_manager.get_connection() as conn:
                cursor = conn.cursor()
                cursor.execute('''
                    DELETE FROM trade_dates WHERE trade_date = ?
                ''', (trade_date,))
                conn.commit()
                logging.info(f"交易日期 {trade_date} 已被删除。")
        except sqlite3.Error as e:
            logging.error(f"删除交易日期失败: {e}")

    def update_trade_date(self, old_date: str, new_date: str):
        """更新指定的交易日期"""
        try:
            with self.db_manager.get_connection() as conn:
                cursor = conn.cursor()
                cursor.execute('''
                    UPDATE trade_dates SET trade_date = ? WHERE trade_date = ?
                ''', (new_date, old_date))
                conn.commit()
                logging.info(f"交易日期 {old_date} 已更新为 {new_date}。")
        except sqlite3.Error as e:
            logging.error(f"更新交易日期失败: {e}")

    def insert_trade_dates(self, trade_dates: List[str]):
        """将交易日期插入数据库，忽略重复的日期"""
        try:
            with self.db_manager.get_connection() as conn:
                for date in trade_dates:
                    conn.execute('''
                        INSERT OR IGNORE INTO trade_dates (trade_date) VALUES (?)
                    ''', (date,))
                conn.commit()
            logging.info(f"成功插入 {len(trade_dates)} 个交易日期。")
        except sqlite3.Error as e:
            logging.error(f"插入交易日期失败: {e}")


# 示例用法
if __name__ == "__main__":
    # 创建DatabaseManager实例
    db_manager = DatabaseManager()

    # 创建TradeDateManager实例
    trade_calendar = TradeDateManager(db_manager)

    # 创建数据获取器实例
    data_fetcher = AKShareDataFetcher(max_retries=3, retry_delay=5, request_delay=1)

    # 获取交易日期
    trade_dates = data_fetcher.fetch_trade_dates(max_retries=3, retry_delay=3, request_delay=0.5)
    if not trade_dates.empty:
        # 将交易日期列表传递给新方法
        trade_calendar.insert_trade_dates(trade_dates['trade_date'].tolist())

    # 获取交易日期列表
    trade_dates_list = trade_calendar.read_trade_dates()
    print("交易日期列表:", trade_dates_list[:5])  # 只打印前5个日期

    # 判断某一天是否为交易日
    test_date = datetime(2023, 10, 10)
    is_trading_day = trade_calendar.is_tool_trading_day(test_date)
    print(f"{test_date.strftime('%Y-%m-%d')} 是否为交易日: {is_trading_day}")

    # 获取偏移交易日期
    offset_days = 1
    input_date = "2023-10-25"
    try:
        previous_trade_date, next_trade_date = trade_calendar.get_offset_trade_dates(input_date, offset_days)
        print(f"输入日期: {input_date}")
        print(f"前一个交易日期: {previous_trade_date}")
        print(f"后一个交易日期: {next_trade_date}")
    except ValueError as e:
        print(e)

    # 获取起始日期和结束日期
    try:
        start_date, end_date = trade_calendar.get_start_end_date("2023-10-25", 5)
        print(f"起始日期: {start_date}, 结束日期: {end_date}")
    except ValueError as e:
        print(e)
